package com.huawei.java.alogrithm;

import com.huawei.java.model.ResultHandle;
import com.huawei.java.model.*;

import java.util.*;

public class WeightAlgorithm {
    public Graph graph;

    // 按照用户节点可以达到的边缘节点数量进行排序，能达到边缘节点数少的优先分配
    public TreeSet<ClientNode> clientNodeTreeSet;

    // key 用户 Map<String, Integer> 每个边缘节点给客户分配的带宽
    private final Map<String, Map<String, Integer>> allocationMaps = new HashMap<>();

    public WeightAlgorithm(Graph graph, TreeSet<ClientNode> clientNodeTreeSet) {
        this.graph = graph;
        this.clientNodeTreeSet = clientNodeTreeSet;
    }

    public void process(Demand demand) {
        // 上一次已经分配成功了
        if (demand.isDistributionSuccess()) {
            return;
        }
        // 重新刷新结果集和带宽
        reloadBandwidth();
        Map<String, Integer> demandMap = demand.getDemandMap();
        for (ClientNode clientNode : clientNodeTreeSet) {
            int clientDemandBandwidth = demandMap.get(clientNode.getName());
            List<SiteNode> validSiteNodes = clientNode.getValidSiteNodes();
            Map<String, Integer> allocationMap = getAllocationByWeight(clientDemandBandwidth, validSiteNodes);
            OptimizeResult optimizeResult = new OptimizeResult();
            optimizeResult.redistribution(allocationMap, graph);
            allocationMaps.put(clientNode.getName(), new HashMap<>(allocationMap));
            allocationMap.clear();
        }
        graph.getSiteNodes().forEach(siteNode -> {
            if (siteNode.getCurrentBandwidth() != siteNode.getTotalBandwidth()) {
                if (siteNode.getAvailableNum() > 0) {
                    siteNode.setAvailableNum(siteNode.getAvailableNum() - 1);
                }
            }
        });
        ResultCompute.store(new HashMap<>(allocationMaps));
        ResultCompute.compute();
        // 记录历次分配的结果
        TimestampResult timestampResult = new TimestampResult(demand.getTimestamp(), new HashMap<>(allocationMaps));
        ResultHandle.timestampResults.add(timestampResult);
    }

    private void reloadBandwidth() {
        for (SiteNode siteNode : graph.getSiteNodes()) {
            siteNode.setCurrentBandwidth(siteNode.getTotalBandwidth());
            siteNode.setUsed(false);
        }
        allocationMaps.clear();
    }

    private Map<String, Integer> getAllocationByWeight(int clientDemandBandwidth, List<SiteNode> validSiteNodes) {
        Map<String, Integer> allocationMap = new HashMap<>();
        long validTotalBandwidth = validSiteNodes.stream().mapToInt(SiteNode::getCurrentBandwidth).sum();
        int clientNeedBandwidth = clientDemandBandwidth;
        validSiteNodes.sort(Comparator.comparingInt(SiteNode::getCurrentBandwidth));
        for (int i = 0; i < validSiteNodes.size(); i++) {
            SiteNode validSiteNode = validSiteNodes.get(i);
            int currentBandwidth = validSiteNode.getCurrentBandwidth();
            int needBandwidth = (int) ((clientDemandBandwidth * (long) currentBandwidth) / validTotalBandwidth);
            if (currentBandwidth == 0) {
                continue;
            }
            // 除法除不尽的，剩下的都给最后一个节点
            if (i == validSiteNodes.size() - 1) {
                validSiteNode.setCurrentBandwidth(currentBandwidth - clientNeedBandwidth);
                allocationMap.put(validSiteNode.getName(), clientNeedBandwidth);
                continue;
            }
            validSiteNode.setCurrentBandwidth(currentBandwidth - needBandwidth);
            allocationMap.put(validSiteNode.getName(), needBandwidth);
            clientNeedBandwidth -= needBandwidth;
        }
        return allocationMap;
    }
}
